package ontocompo.ui.projectmanagement;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import org.jdom.CDATA;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import ontocompo.ui.appmanagement.Application;
import ontocompo.ui.appmanagement.ApplicationManager;
import ontocompo.ui.global.Resources;
import ontocompo.ui.positioning.GridRelativePane;
import ontocompo.ui.positioning.RelativePosition;
import ontocompo.ui.screenmanagement.Screen;
import ontocompo.ui.screenmanagement.ScreenManager;

public class ProjectManager implements ActionListener {

	private JTextField projectNameField;
	
	private JComboBox availableProjects;
	
	private ApplicationManager appManager;
	private ScreenManager screenManager;
	
	public ProjectManager(ApplicationManager appManager, ScreenManager screenManager) {
		this.appManager = appManager;
		this.screenManager = screenManager;
	}
	
	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		JMenuItem jmi = (JMenuItem) arg0.getSource();
		
		if(jmi.getName().equals("saveproject")) {
			JPanel popupPanel = this.getSavePanel();
			//this.popup = pf.getPopup(null, popupPanel, (java.awt.Toolkit.getDefaultToolkit().getScreenSize().width-popupPanel.getSize().width)/2, (java.awt.Toolkit.getDefaultToolkit().getScreenSize().height-popupPanel.getSize().height)/2);
			//this.popup.show();
			Object[] options = {"Cancel","Ok"};
			int retour = JOptionPane.showOptionDialog(null, popupPanel, "Save Current Project", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[1]);
			if(retour == 1) {
				saveAction();
			}
		}
		
		if(jmi.getName().equals("openproject")) {
			JPanel popupPanel = this.getOpenPanel();
			//this.popup = pf.getPopup(null, popupPanel, (java.awt.Toolkit.getDefaultToolkit().getScreenSize().width-popupPanel.getSize().width)/2, (java.awt.Toolkit.getDefaultToolkit().getScreenSize().height-popupPanel.getSize().height)/2);
			//this.popup.show();
			Object[] options = {"Cancel","Ok"};
			int retour = JOptionPane.showOptionDialog(null, popupPanel, "Open An OntoCompo Project", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[1]);
			if(retour == 1) {
				openAction();
			}
		}
	}
	
	private JPanel getSavePanel() {
		JPanel jpanel = new JPanel();
		jpanel.setBackground(Color.WHITE);
		jpanel.setLayout(new BorderLayout());

		JLabel jlabel = new JLabel("Project Name:");
		jpanel.add(jlabel, BorderLayout.NORTH);

		this.projectNameField = new JTextField();
		
		jpanel.add(this.projectNameField, BorderLayout.CENTER);

		return jpanel;
	}
	
	private JPanel getOpenPanel() {
		JPanel jpanel = new JPanel();
		jpanel.setBackground(Color.WHITE);
		jpanel.setLayout(new BorderLayout());

		JLabel jlabel = new JLabel("Select The Project To Load:");
		jpanel.add(jlabel, BorderLayout.NORTH);
		
		File projectsFolder = new File("./resources/projects/");
		
		String[] projectsList = projectsFolder.list();
		
		this.availableProjects = new JComboBox(projectsList);
		
		jpanel.add(this.availableProjects, BorderLayout.CENTER);

		return jpanel;
	}
	
	private void saveAction() {
		String projectName = this.projectNameField.getText();
		
		Element xmlRoot = new Element("ocp");
		
		Element xmlProjectName = new Element("name");
		xmlProjectName.setContent(new CDATA(projectName));
		xmlRoot.addContent(xmlProjectName);
		
		Element xmlLoadedApplications = new Element("loadedapplications");
		
		
		for(Application app: Resources.LOADEDAPPLICATIONS) {
			Element xmlLoadedApp = new Element("loadedapp");
			xmlLoadedApp.setContent(new CDATA(app.getName()));
			xmlLoadedApplications.addContent(xmlLoadedApp);
		}
		
		xmlRoot.addContent(xmlLoadedApplications);
		
		Element xmlScreens = new Element("screens");
		
		for(Screen s: this.screenManager.getAvailabledScreens()) {
			Element xmlScreen = new Element("screen");
			
				Element xmlScreenName = new Element("screenname");
				xmlScreenName.setContent(new CDATA(s.getName()));
				xmlScreen.addContent(xmlScreenName);
				
				Element xmlScreenContent = new Element("screencontent");
				
					Element xmlScreenInBulk = new Element("screeninbulk");
					
					for(Component jc: s.getInBulkComponents()) {
						String jcUri = this.appManager.getUriJComponent(jc);
						if(jcUri != null) {
							Element xmlInBulkComponent = new Element("inbulkcomponent");
							xmlInBulkComponent.setContent(new CDATA(jcUri));
							xmlScreenInBulk.addContent(xmlInBulkComponent);
						}
					}
					
					xmlScreenContent.addContent(xmlScreenInBulk);
					
					Element xmlScreenRoot = new Element("screenroot");
					GridRelativePane grpScreenRoot = s.getRootScreen();
					if(grpScreenRoot != null) {
						Element xmlScreenGridRelativePane = this.getXmlRepresentationOfGridRelativePane(grpScreenRoot);
						xmlScreenRoot.addContent(xmlScreenGridRelativePane);
					}
					xmlScreenContent.addContent(xmlScreenRoot);
				
				xmlScreen.addContent(xmlScreenContent);
			
			xmlScreens.addContent(xmlScreen);
		}
		
		xmlRoot.addContent(xmlScreens);

		Document xmlDocument = new Document(xmlRoot);
		XMLOutputter outputter = new XMLOutputter();
		outputter.setFormat(Format.getPrettyFormat());
		try {
			File outputFile = new File("./resources/projects/" + projectName.trim().toLowerCase() + ".ocp");
			outputter.output(xmlDocument, new FileOutputStream(outputFile));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private Element getXmlRepresentationOfGridRelativePane(GridRelativePane grp) {
		Element grpElem = new Element("gridrelativepane");
		
			JComponent centeredComponent = grp.getCenteredComponent();
			
//		if(centeredComponent != null) {
				String jcUri = this.appManager.getUriJComponent(centeredComponent);
				if(jcUri != null) {
					Element grpCenteredComponent = new Element("centeredcomponent");
					grpCenteredComponent.setContent(new CDATA(jcUri));
					grpElem.addContent(grpCenteredComponent);
				}
				
			GridRelativePane grpTopLeft = grp.getTopleft();
			if(grpTopLeft != null) {
				Element grpTopLeftElement = new Element("topleft");
				grpTopLeftElement.addContent(this.getXmlRepresentationOfGridRelativePane(grpTopLeft));
				grpElem.addContent(grpTopLeftElement);
			}
			
			GridRelativePane grpTop = grp.getTop();
			if(grpTop != null) {
				Element grpTopElement = new Element("top");
				grpTopElement.addContent(this.getXmlRepresentationOfGridRelativePane(grpTop));
				grpElem.addContent(grpTopElement);
			}
			
			GridRelativePane grpTopRight = grp.getTopright();
			if(grpTopRight != null) {
				Element grpTopRightElement = new Element("topright");
				grpTopRightElement.addContent(this.getXmlRepresentationOfGridRelativePane(grpTopRight));
				grpElem.addContent(grpTopRightElement);
			}
			
			GridRelativePane grpLeft = grp.getLeft();
			if(grpLeft != null) {
				Element grpLeftElement = new Element("left");
				grpLeftElement.addContent(this.getXmlRepresentationOfGridRelativePane(grpLeft));
				grpElem.addContent(grpLeftElement);
			}
			
			GridRelativePane grpRight = grp.getRight();
			if(grpRight != null) {
				Element grpRightElement = new Element("right");
				grpRightElement.addContent(this.getXmlRepresentationOfGridRelativePane(grpRight));
				grpElem.addContent(grpRightElement);
			}
			
			GridRelativePane grpBottomLeft = grp.getBottomleft();
			if(grpBottomLeft != null) {
				Element grpBottomLeftElement = new Element("bottomleft");
				grpBottomLeftElement.addContent(this.getXmlRepresentationOfGridRelativePane(grpBottomLeft));
				grpElem.addContent(grpBottomLeftElement);
			}
			
			GridRelativePane grpBottom = grp.getBottom();
			if(grpBottom != null) {
				Element grpBottomElement = new Element("bottom");
				grpBottomElement.addContent(this.getXmlRepresentationOfGridRelativePane(grpBottom));
				grpElem.addContent(grpBottomElement);
			}
			
			GridRelativePane grpBottomRight = grp.getBottomright();
			if(grpBottomRight != null) {
				Element grpBottomRightElement = new Element("bottomright");
				grpBottomRightElement.addContent(this.getXmlRepresentationOfGridRelativePane(grpBottomRight));
				grpElem.addContent(grpBottomRightElement);
			}
//		}
		
		return grpElem;
	}
	
	private void openAction() {
		//TODO Réinitialiser l'application en proposant de sauvegarder le projet courant
		
		String projectName = (String) this.availableProjects.getSelectedItem();
		
		SAXBuilder builder = new SAXBuilder();
		try {
			File f = new File("./resources/projects/" + projectName);

			if(f.exists()) {

				Element xmlRoot = builder.build(f).getRootElement();

				Element loadedApplicationsElement = xmlRoot.getChild("loadedapplications");
				
				List<Element> loadedApps = loadedApplicationsElement.getChildren("loadedapp");
				
				if(loadedApps.size() != 0) {
					for(Element loadedAppElem: loadedApps) {
						String appName = loadedAppElem.getText();
						Application app = null;
						
						for(Application a: Resources.ONTOCOMPOAPPLICATIONS) {
							if(a.getName().equals(appName)) {
								app = a;
							}
						}
						
						if(app != null) {
							this.appManager.loadApplication(app);
						}
					}
					
					Element screensElement = xmlRoot.getChild("screens");
					
					List<Element> screens = screensElement.getChildren("screen");
					
					if(screens.size() != 0) {
						for(Element screenElement : screens) {
							String screenName = screenElement.getChildText("screenname");
							
							Screen s = new Screen(screenName);
							
							Element screenContent = screenElement.getChild("screencontent");
							
							Element screenInBulk = screenContent.getChild("screeninbulk");
							
							List<Element> inBulkComponentElements = screenInBulk.getChildren("inbulkcomponent");
							
							for(Element inBulkComponentElem : inBulkComponentElements) {
								String jcUri = inBulkComponentElem.getText();
								
								Application app = this.appManager.getApplicationOfJComponentUri(jcUri);
								
								if(app != null) {
									JComponent jc = app.getJComponentFromComponentUid(jcUri);
									
									JComponent jcExtracted = app.extractComponent(jc);
									
									s.addInBulk(jcExtracted);
								}
								
							}
							
							Element screenRoot = screenContent.getChild("screenroot");
							
							Element screenRootGridRelativePaneElem = screenRoot.getChild("gridrelativepane");
							
							if(screenRootGridRelativePaneElem != null) {
								GridRelativePane grp = this.retrieveGridRelativePane(screenRootGridRelativePaneElem);
								s.setRootScreen(grp);
							}
							
							this.screenManager.addScreen(s);
						}
					}
				}
				
				
			}

		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private GridRelativePane retrieveGridRelativePane(Element grpElem) {
		String centeredComponentUri = grpElem.getChildText("centeredcomponent");
		
		Application app = this.appManager.getApplicationOfJComponentUri(centeredComponentUri);
		
		if(app != null) {
			JComponent jc = app.getJComponentFromComponentUid(centeredComponentUri);
			
			JComponent jcExtracted = app.extractComponent(jc);
			
		
			GridRelativePane grp = new GridRelativePane(jcExtracted);
			
			Element topLeftElem = grpElem.getChild("topleft");
			if(topLeftElem != null) {
				Element positionGridRelativePaneElem = topLeftElem.getChild("gridrelativepane");
				
				GridRelativePane positionGrp = this.retrieveGridRelativePane(positionGridRelativePaneElem);
				
				grp.addOnTopLeft(positionGrp);
			}
			
			Element topElem = grpElem.getChild("top");
			if(topElem != null) {
				Element positionGridRelativePaneElem = topElem.getChild("gridrelativepane");
				
				GridRelativePane positionGrp = this.retrieveGridRelativePane(positionGridRelativePaneElem);
				
				grp.addOnTop(positionGrp);
			}
			
			Element topRightElem = grpElem.getChild("topright");
			if(topRightElem != null) {
				Element positionGridRelativePaneElem = topRightElem.getChild("gridrelativepane");
				
				GridRelativePane positionGrp = this.retrieveGridRelativePane(positionGridRelativePaneElem);
				
				grp.addOnTopRight(positionGrp);
			}
			
			Element leftElem = grpElem.getChild("left");
			if(leftElem != null) {
				Element positionGridRelativePaneElem = leftElem.getChild("gridrelativepane");
				
				GridRelativePane positionGrp = this.retrieveGridRelativePane(positionGridRelativePaneElem);
				
				grp.addOnLeft(positionGrp);
			}
			
			Element rightElem = grpElem.getChild("right");
			if(rightElem != null) {
				Element positionGridRelativePaneElem = rightElem.getChild("gridrelativepane");
				
				GridRelativePane positionGrp = this.retrieveGridRelativePane(positionGridRelativePaneElem);
				
				grp.addOnRight(positionGrp);
			}
			
			Element bottomLeftElem = grpElem.getChild("bottomleft");
			if(bottomLeftElem != null) {
				Element positionGridRelativePaneElem = bottomLeftElem.getChild("gridrelativepane");
				
				GridRelativePane positionGrp = this.retrieveGridRelativePane(positionGridRelativePaneElem);
				
				grp.addOnBottomLeft(positionGrp);
			}
			
			Element bottomElem = grpElem.getChild("bottom");
			if(bottomElem != null) {
				Element positionGridRelativePaneElem = bottomElem.getChild("gridrelativepane");
				
				GridRelativePane positionGrp = this.retrieveGridRelativePane(positionGridRelativePaneElem);
				
				grp.addOnBottom(positionGrp);
			}
			
			Element bottomRightElem = grpElem.getChild("bottomright");
			if(bottomRightElem != null) {
				Element positionGridRelativePaneElem = bottomRightElem.getChild("gridrelativepane");
				
				GridRelativePane positionGrp = this.retrieveGridRelativePane(positionGridRelativePaneElem);
				
				grp.addOnBottomRight(positionGrp);
			}
			
			return grp;
		}
		
		return null;
	}

}
